﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace ParserDSV
{
    class Program
    {
        static char delim = ',';
        static int  linea = 0;

        static void Main (string [] args)
        {
            using (StreamReader sr = File.OpenText ("file.txt"))
            {
                string renglon = string.Empty;

                while (null != (renglon = sr.ReadLine()))
                {
                    linea ++;

                    if (! renglon.Trim().StartsWith("#")) // si no es un comentario
                        mostrar(trabajar(renglon));
                }

                sr.Close ();
            }
        }

        private static void mostrar (List<string> lista)
        {
            Console.Write("El renglon tiene {0} objetos: ", lista.Count);
            int color = 0;

            foreach (var x in lista)
            {
                color++;
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.Write("[");
                Console.ForegroundColor = (ConsoleColor)(color % 15) + 1;
                Console.Write("{0}", x);
                Console.ForegroundColor = ConsoleColor.Gray;
                Console.Write("]");
            }

            Console.WriteLine ();
        }

        private static List<string> trabajar (string renglon)
        {
            var lista   = new List<string>();
            var index   = 0;
            var objeto  = new StringBuilder();

            while (index < renglon.Length)
            {
                if (delim == renglon[index])
                {
                    lista.Add(objeto.ToString());
                    objeto = new StringBuilder();
                }
                else if ('#' == renglon[index])
                {
                    break;
                }
                else if ('\\' == renglon[index])
                {
                    index++;

                    // si no hay nada después de un \
                    if (!(index < renglon.Length)) 
                        parseErrorAndDie(
                            "Falta el caracter de escape después de '\\'",
                            renglon, index
                        );
                    else if ('\\' == renglon[index])
                        objeto.Append('\\');
                    else if ('n' == renglon[index])
                        objeto.Append('\n');
                    else if ('r' == renglon[index])
                        objeto.Append('\r');
                    else if ('#' == renglon[index])
                        objeto.Append('#');
                    else if (delim == renglon[index])
                        objeto.Append(delim);
                    else
                        parseErrorAndDie(
                            string.Format("Secuencia de escape '{0}' no reconocida",
                            renglon[index]), renglon, index + 1
                        );
                }
                else
                {
                    objeto.Append(renglon[index]);
                }

                index++;
            }

            lista.Add (objeto.ToString());
            return lista;
        }

        static void parseErrorAndDie (string mensaje, string renglon, int col)
        {
            Console.ForegroundColor = ConsoleColor.Gray;
            Console.WriteLine       (renglon.Substring(0, col));
            Console.ForegroundColor = ConsoleColor.Red;
            string  pad             = new string(' ', (col - 1) % Console.BufferWidth);
            Console.WriteLine       (pad + "^");
            Console.WriteLine       (pad + "|");
            Console.WriteLine       ("Parsing error: {0}, lin {1} col {2}", mensaje, linea, col);
            Console.ForegroundColor = ConsoleColor.Gray;
            Environment.Exit        (-1);
        }
    }
}
